package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.RoleResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;
    @Cacheable(value = CacheConstant.RESOURCE_LIST ,key ="#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> list(ResourceDto resourceDto) {
        List<Resource> resource = resourceMapper.selectList(resourceDto);
        return BeanUtil.copyToList(resource,ResourceVo.class);


    }

    @Cacheable(value = CacheConstant.RESOURCE_TREE )
    @Override
    public TreeVo getTree(ResourceDto resourceDto) {
        resourceDto.setResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID));
        resourceDto.setResourceType(SuperConstant.MENU);
        resourceDto.setDataState(SuperConstant.DATA_STATE_0);
        //查询全部菜单
        List<Resource> resources = resourceMapper.selectList(resourceDto);
        Resource root = new Resource();
        root.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        root.setResourceName("智慧养老院");
        //把菜单数据封装成树型结构
        List<TreeItemVo> items = new ArrayList<>();
        recursionTreeItem(items,root,resources);
        return new TreeVo(items);
    }


    private void recursionTreeItem(List<TreeItemVo> itemVos,Resource root,List<Resource> resources) {
        //第一次调用 根据根节点resource创建 TreeItemVo
        TreeItemVo treeItemVo = TreeItemVo.builder().id(root.getResourceNo()).label(root.getResourceName()).build();

        //第一次调用 找出根节点的一级菜单
        //拿到包含父元素于root.getResourceNo()的资源
        List<Resource> childrenList = resources.stream().filter(n->n.getParentResourceNo().equals(root.getResourceNo())).collect(Collectors.toList());
        //判断传入的是否为空
        if(!EmptyUtil.isNullOrEmpty(childrenList)){
            List<TreeItemVo> childrenListItem = new ArrayList<>();

            childrenList.forEach(resource->{
                recursionTreeItem(childrenListItem,resource,resources);
            });
            treeItemVo.setChildren(childrenListItem);
        }
        itemVos.add(treeItemVo);
    }

    @Caching(evict = {@CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)})
    @Override
    public void createResource(ResourceDto resourceDto) {
        Resource resource=BeanUtil.toBean(resourceDto,Resource.class);
        //查询父类获取状态--设置到当前的DTO对象
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        resource.setDataState(parentResource.getDataState());
        boolean isIgnore = true;
        //判断是否是按钮，如果是按钮不对其进行判断
        //判断是否是按钮，如果是按钮，则不限制层级
        if(StringUtils.isNotEmpty(resourceDto.getResourceType())
                && resourceDto.getResourceType().equals(SuperConstant.BUTTON)){
            isIgnore=false;
        }
        //根据父级生成编号
        String resourceNo = createResourceNo(resourceDto.getParentResourceNo(),isIgnore);
        //当前Dto对象设置资源编号
        resource.setResourceNo(resourceNo);
        //执行插入保存操作
        resourceMapper.insert(resource);

    }
    /**
     * 创建资源的编号
     * @param parentResourceNo
     * @return
     */
    private String createResourceNo(String parentResourceNo,boolean isIgnore) {

        //判断资源编号是否大于三级
        //100 001 000 000 000
        //100 001 001 000 000
        //100 001 001 001 000
        //100 001 001 001 001 001
        if(isIgnore && NoProcessing.processString(parentResourceNo).length() / 3 >= 5){
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //根据父资源编号查询子资源
        ResourceDto dto = ResourceDto.builder().parentResourceNo(parentResourceNo).build();
        List<Resource> resources = resourceMapper.selectList(dto);
        if(EmptyUtil.isNullOrEmpty(resources)){
            //无下属节点，创建新的节点编号  100 001 001 001 000--->100 001 001 001 001
            return NoProcessing.createNo(parentResourceNo,false);
        }else {
            //有下属节点，在已有的节点上追加
            //先获取已有节点的最大值--100001003000000
            Long maxNo = resources.stream().map(resource -> {
                return Long.valueOf(resource.getResourceNo());
            }).max(Comparator.comparing(i -> i)).get();

            return NoProcessing.createNo(String.valueOf(maxNo),true);
        }
    }

    /**
     * 修改资源
     * @param resourceDto
     */
    @Caching(evict = {@CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true)})
    @Override
    public void updateResource(ResourceDto resourceDto) {
        //转换
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        int flag = resourceMapper.updateByPrimaryKeySelective(resource);
        if (flag == 0) {
            throw new RuntimeException("修改资源信息出错");
        }
    }

    /**
     * 启用禁用
     * @param resourceVo
     * @return
     */
    @Caching(evict = {@CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true)})
    @Override
    public void isEnable(ResourceVo resourceVo) {
        //启用菜单
        if (resourceVo.getDataState().equals("0")) {
            //判断父级菜单是否是禁用，如果是禁用，不允许启用
            String parentResourceNo = resourceVo.getParentResourceNo();
            Resource parentResource = resourceMapper.selectByResourceNo(parentResourceNo);
            if (parentResource != null && parentResource.getDataState().equals("1")) {
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }
        //TODO 当按钮被分配的时候，出错误提示：按钮已分配，不允许禁用   已完成
        int count = roleResourceMapper.checkMenuExistRole(resourceVo.getResourceNo());
        if (resourceVo.getDataState().equals("1") && count > 0) {
            Resource resource = resourceMapper.selectByResourceNo(resourceVo.getResourceNo());
            if(resource.getResourceType().equals("m")){
                throw new BaseException(BasicEnum.MENU_DISTRIBUTED);
            }else {
                throw new BaseException(BasicEnum.BUTTON_DISTRIBUTED);
            }
        }


        //判断是否有子菜单，如果有子菜单，则一起启用或禁用
        String resourceNo = resourceVo.getResourceNo();
        resourceMapper.updateByResourceNo(resourceNo, resourceVo.getDataState());
        resourceMapper.updateByParentResourceNo(NoProcessing.processString(resourceNo), resourceVo.getDataState());
    }

    /**
     * 删除菜单
     * @param resourceNo
     */
    @Caching(evict = {@CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true)})
    @Override
    public void deleteByResourceNo(String resourceNo) {
        if (hasChildByMenuId(resourceNo)) {
            throw new RuntimeException("存在子菜单,不允许删除");
        }

        //TODO 如果当前菜单被角色引用，则不能删除 已完成
        if (checkMenuExistRole(resourceNo)) {
            throw new RuntimeException("菜单已分配,不允许删除");
        }

        Resource resource = resourceMapper.selectByResourceNo(resourceNo);
        if(resource == null || resource.getDataState().equals(SuperConstant.DATA_STATE_0)){
            throw new RuntimeException("菜单启用状态,不能删除");
        }

        resourceMapper.deleteByResourceNo(resourceNo);
    }

    /**
     * 根据用户id查询对应的资源数据
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if (CollUtil.isEmpty(menuVoList)) {
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组（parentNo:[{},{}]）
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        for (MenuVo menuVo : menuVoList) {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/"+menuVo.getName());
            //根据父编号到map中查找是否包含子菜单，如果包含则设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(menuVos)){
                menuVos.forEach(m->{
                    m.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
                    m.setRedirect(m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        }
        //根据根编号查找所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }

    @Autowired
    private RoleResourceMapper roleResourceMapper;

    /**
     * 查询菜单使用数量
     *
     * @param resourceNo 菜单编号
     * @return 结果
     */
    public boolean checkMenuExistRole(String resourceNo) {
        int result = roleResourceMapper.checkMenuExistRole(resourceNo);
        return result > 0 ? true : false;
    }



    /**
     * 判断是否有子菜单
     * @param resourceNo
     * @return
     */
    private boolean hasChildByMenuId(String resourceNo) {
        int result = resourceMapper.hasChildByMenuId(resourceNo);
        return result > 0 ? true : false;
    }


}
